---
title: "Introduction"
group: "Getting Started"
groupOrder: 0
---

`zsa` is the best library for building typesafe server actions in NextJS. Built for a simple, scalable developer experience. Some majors features include...

- Validated inputs/outputs with zod (hence the name *Zod Server Actions*)
- Procedures (aka middleware) that pass context to your server actions
- [React Query](https://tanstack.com/query/latest/docs/framework/react/overview) integration for querying server actions in client components

_and much more!_

To get started, you can install `zsa` using any package manager:

```bash
npm i zsa zsa-react zod
```

<Note>
  [Zod](https://zod.dev/) provides a simple way to define and validate types in
  your code.
</Note>

## Creating your first action

There's plenty of functionality with `zsa`, but to start, here is how you make a simple, validated server action:

_(we know this function is silly but it gets the point across)_

```ts title="actions.ts"
"use server"

import { createServerAction } from "zsa"
import z from "zod"

export const incrementNumberAction = createServerAction() // [!code highlight]
    .input(z.object({
        number: z.number()
    }))
    .handler(async ({ input }) => {
        // Sleep for .5 seconds
        await new Promise((resolve) => setTimeout(resolve, 500))
        // Increment the input number by 1
        return input.number + 1;
    });
```

Let's break down the code:

- `createServerAction` initializes a server action.
- `input` sets the input schema for the action using a Zod schema.
- `handler` sets the handler function for the action. **The input is automatically validated based on the input schema.**

<Info>
  A `ZSAError` with the code `INPUT_PARSE_ERROR` will be returned if the
  handler's input is does not match input schema.
</Info>

## Calling from the server

Server actions can also be called directly from the server without the need for a try/catch block.

```ts title="example.ts"
"use server"

const [data, err] = await incrementNumberAction({ number: 24 }); // [!code highlight]

if (err) {
    return;
} else {
    console.log(data); // 25
}
```

The action will return either `[data, null]` on success or `[null, err]` on error.

## Calling from the client

The most lightweight way to call your server action is to just call it! That is the beauty of server actions.

```tsx title="increment-example.tsx"
"use client"

import { incrementNumberAction } from "./actions";
import { useState } from "react";
import { Button, Card, CardContent, CardDescription, CardHeader, CardTitle } from "ui";

export default function IncrementExample() {
    const [counter, setCounter] = useState(0);
    return (
        <Card>
            <CardHeader>
                <CardTitle>Increment Number</CardTitle>
            </CardHeader>
            <CardContent className="flex flex-col gap-4">
                <Button
                    onClick={async () => {
                        const [data, err] = await incrementNumberAction({ // [!code highlight]
                            number: counter, // [!code highlight]
                        }) // [!code highlight]

                        if (err) {
                            // handle error
                            return
                        }

                        setCounter(data);
                    }}
                >
                    Invoke action
                </Button>
                <p>Count:</p>
            </CardContent>
        </Card>
    );
}
```

However, usually you will want to use the `useServerAction` hook to make your life easier.

Server actions come with built-in loading states, making it easy to handle asynchronous operations. Here's an example of using the `incrementNumberAction` as a mutation:

```tsx title="increment-example.tsx"
"use client"

import { incrementNumberAction } from "./actions";
import { useServerAction } from "zsa-react";
import { useState } from "react";
import { Button, Card, CardContent, CardDescription, CardHeader, CardTitle } from "ui";

export default function IncrementExample() {
    const [counter, setCounter] = useState(0);
    const { isPending, execute, data } = useServerAction(incrementNumberAction); // [!code highlight]

    return (
        <Card>
            <CardHeader>
                <CardTitle>Increment Number</CardTitle>
            </CardHeader>
            <CardContent className="flex flex-col gap-4">
                <Button
                    disabled={isPending} // [!code highlight]
                    onClick={async () => {
                        const [data, err] = await execute({ // [!code highlight]
                            number: counter, // [!code highlight]
                        }) // [!code highlight]

                        if (err) {
                            // handle error
                            return
                        }

                        setCounter(data);
                    }}
                >
                    Invoke action
                </Button>
                <p>Count:</p>
                <div>{isPending ? "saving..." : data}</div> // [!code highlight]
            </CardContent>
        </Card>
    );
}
```

- `useServerAction` allows you to use this server action from within your client components.
- `execute` executes the server action endpoint with the typesafe input directly from `onClick`.

Here is the result:

<ExampleComponent id="increment-example" />

Thats just the beginning... Continue reading to learn more about `zsa`!

<Note>
  To use server actions for querying/refetching data from the client side, visit
  the [Client Side Usage](/docs/react-query) section.
</Note>
